﻿// Copyright (c) 2011 Vratislav Cermak (vratacermak@gmail.com)
//  
// This file is part of SrtSync Project. See http://code.google.com/p/srtsync/ for more information.
//  
// SrtSync is an open source project. Using of SrtSync is free of charge.
// It is distributed under GNU General Public License version 3 (GPLv3).
// GPLv3 can be found at http://www.gnu.org/licenses/gpl.html.
//  
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE.  See the license for more details.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace SrtSync.Core
{
    internal class SrtReader
    {
        private enum CurrentData
        {
            Index,
            Time,
            Text
        }

        private List<Entry> _entries;

        public IEnumerable<Entry> Entries
        {
            get
            {
                return _entries;
            }
        }

        public void Clear()
        {
            _entries = null;
        }

        public void Load(string path, Encoding encoding)
        {
            _entries = new List<Entry>();

            using (StreamReader reader = new StreamReader(path, encoding))
            {
                string line;
                Entry entry = new Entry();
                List<string> texts = new List<string>();
                CurrentData currentData = CurrentData.Index;
                while ((line = reader.ReadLine()) != null)
                {
                    switch (currentData)
                    {
                        case CurrentData.Index:
                            if (String.IsNullOrEmpty(line))
                            {
                                continue;
                            }
                            entry.Index = Int32.Parse(line);
                            currentData = CurrentData.Time;
                            break;
                        case CurrentData.Time:
                            entry.Time = line;
                            currentData = CurrentData.Text;
                            break;
                        case CurrentData.Text:
                            if (String.IsNullOrEmpty(line.Trim()))
                            {
                                entry.Texts = texts.ToArray();
                                _entries.Add(entry);

                                texts.Clear();
                                entry = new Entry();
                                currentData = CurrentData.Index;
                            }
                            else
                            {
                                texts.Add(line);
                            }
                            break;
                    }
                }
                if (currentData == CurrentData.Text)
                {
                    entry.Texts = texts.ToArray();
                    _entries.Add(entry);
                }
            }
            
            FixIdxs();
        }

        public void Replace(IEnumerable<Entry> oldEntries, IEnumerable<Entry> newEntries)
        {
            int firstIndex = _entries.IndexOf(oldEntries.First());

            _entries.RemoveAll(x => oldEntries.Contains(x));
            _entries.InsertRange(firstIndex, newEntries);

            FixIdxs();
        }

        public Entry Merge(IEnumerable<Entry> entries)
        {
            List<string> texts = new List<string>();
            Entry first = entries.First(x => true);
            string lastTime = null;

            foreach (Entry entry in entries)
            {
                texts.AddRange(entry.Texts);
                lastTime = entry.Time;

                if (entry != first)
                {
                    _entries.Remove(entry);
                }
            }

            first.Texts = texts.ToArray();

            // update time in first entry
            if (!String.IsNullOrEmpty(lastTime) && !String.IsNullOrEmpty(first.Time))
            {
                string firstPart = first.Time.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[0];
                string secondPart = lastTime.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[2];
                first.Time = String.Format("{0} --> {1}", firstPart, secondPart);
            }

            FixIdxs();

            return entries.First();
        }

        public void Delete(IEnumerable<Entry> entries)
        {
            _entries.RemoveAll(x => entries.Contains(x));

            FixIdxs();
        }

        private void FixIdxs()
        {
            int counter = 1;
            foreach (var entry in _entries)
            {
                entry.Index = counter++;
            }
        }
    }
}